<?php

declare(strict_types=1);

namespace App\Lib\Mongo;

use Hyperf\Task\Annotation\Task;
use MongoDB\Driver\BulkWrite;
use MongoDB\Driver\Manager;
use MongoDB\Driver\Query;
use MongoDB\Driver\WriteConcern;
use MongoDB\Driver\Command;

class MongoDriver
{
    /**
     * @var Manager
     */
    public $manager;
    //表名的前缀
    protected $prefix;

    //数据库名
    protected $dbname;

    public function __construct()
    {
        if ($this->manager instanceof Manager) {
            return $this->manager;
        }
        //配置从数据库取
        $config = config('mongodb.default');
        $this->prefix = $config['prefix'];
        $this->dbname = $config['db'];
        $uri = "mongodb://{$config['username']}:{$config['password']}@{$config['host']}:{$config['port']}/{$config['db']}";
        return $this->manager = new Manager($uri, []);
    }

    /**
     * @param string $table  表名
     * @param array $document  插入的数据
     * @return int 返回插入的行数
     * @Description 插入数据
     * @example $document
     * [
     * 'status'=>5 
     * ]
     * @author wuxian
     * @since 2020-04-20
     */
    public function insert(string $table, array $document)
    {
        $writeConcern = new WriteConcern(WriteConcern::MAJORITY, 1000);
        $bulk = new BulkWrite();
        $id = $bulk->insert($document);
        $namespace = $this->dbname.'.'.$this->prefix.$table;
        $result = $this->manager->executeBulkWrite($namespace, $bulk, $writeConcern);
        return $result->getInsertedCount();
    }

    /**
     * @param string $table  表名
     * @param array $document  插入的数据
     * @return string 返回插入的主键id
     * @Description 插入数据
     * @example $document
     * [
     * 'status'=>5 
     * ]
     * @author wuxian
     * @since 2020-04-20
     */
    public function insertGetId(string $table, array $document)
    {
        $writeConcern = new WriteConcern(WriteConcern::MAJORITY, 1000);
        $bulk = new BulkWrite();
        $id = $bulk->insert($document);
        $namespace = $this->dbname.'.'.$this->prefix.$table;
        $result = $this->manager->executeBulkWrite($namespace, $bulk, $writeConcern);
        return $id;
    }

    /**
     * @param string $table  表名
     * @param array $document  插入的数据
     * @return int 返回插入的行数
     * @Description 插入数据
     * @example $document
     * [
     *      [
     *          'status'=>5 
     *      ],
     *      [
     *          'status'=>4
     *      ]
     * ]
     * @author wuxian
     * @since 2020-04-20
     */
    public function insertMany(string $table, array $document)
    {
        $writeConcern = new WriteConcern(WriteConcern::MAJORITY, 1000);
        $bulk = new BulkWrite();
        foreach($document as $v){
            $id = $bulk->insert($v);
        }
        $namespace = $this->dbname.'.'.$this->prefix.$table;
        $result = $this->manager->executeBulkWrite($namespace, $bulk, $writeConcern);
        return $result->getInsertedCount();
    }

    /**
     * @param string $table 表名
     * @param array $filter  查询条件
     * @param array $document  更新的数据
     * @return int
     * @Description  更新数据
     * @example
     * $filter
     * [
     * 'status'=>5  //状态等于5的数据
     * ]
     * $document
     * [
     * 'status'=>4  //把状态等于5改成4
     * ]
     * @author wuxian
     * @since 2020-04-20
     */
    public function update(string $table, array $filter = [], array $document)
    {
        if(empty($filter)){
            throw new \Exception("更新条件不能为空");
            return;
        }
        $writeConcern = new WriteConcern(WriteConcern::MAJORITY, 1000);
        $bulk = new BulkWrite();
        $bulk->update($filter,['$set'=>$document],['multi' => true,'upsert' => false]);
        $namespace = $this->dbname.'.'.$this->prefix.$table;
        $result = $this->manager->executeBulkWrite($namespace, $bulk, $writeConcern);
        return $result->getModifiedCount();
    }

    /**
     * @param string $table 表名
     * @param array $filter 查询条件
     * @return int
     * @Description  删除数据
     * @example $filter
     * [
     *      'status'=>5  //状态等于5的数据
     * ]
     * @author wuxian
     * @since 2020-04-20
     */
    public function delete(string $table, array $filter = [])
    {
        if(empty($filter)){
            throw new \Exception("删除条件不能为空");
            return;
        }
        $writeConcern = new WriteConcern(WriteConcern::MAJORITY, 1000);
        $bulk = new BulkWrite();
        $bulk->delete($filter,['limit' => 0]);
        $namespace = $this->dbname.'.'.$this->prefix.$table;
        $result = $this->manager->executeBulkWrite($namespace, $bulk, $writeConcern);
        return $result->getDeletedCount();
    }

    /**
     * @param string $table 表名
     * @param array $filter 查询条件
     * @param array $options 查询数据结构选项
     * @return array
     * @Description  查询数据
     * @example  $filter
     * [
     *       'status'=>5  //状态等于5的数据
     * ]
     * @author wuxian
     * @since 2020-04-20
     */
    public function query(string $table, array $filter = [], array $options = [])
    {
        $query = new Query($filter, $options);
        $namespace = $this->dbname.'.'.$this->prefix.$table;
        $cursor = $this->manager->executeQuery($namespace, $query);
        return $cursor->toArray();
    }

    /**
     * @param [type] $pipeline
     * @return void
     * @Description  执行mongo的原始命令
     * @example
     * $arr = [
     *     'aggregate' => 'pc_test',
     *     'pipeline' => [      
     *           ['$project'=>[
     *                  'status'=>1,
     *                   'user_id'=>1,
     *                    'real_amount'=>1,
     *                   'openid'=>1,
     *                  'yearSubstring'=>['$substr'=>['$add_time',0,8]],
     *                  'temp'=>['$convert'=>['input'=>'$add_time','to'=>'double']],
     *                   'tmpcoupon'=>['$toInt'=>'$coupon_id'],
     *                 'yearMonthDayUTC'=>['$convert'=>[ 'format'=>'%Y-%m-%d', 'date'=> '$add_time' ] ],
     *              ]
     *          ],
     *           [
     *                '$match' => [
     *                   'temp' => ['$gt'=>20200419235600],
     *               ]
     *            ],
     *          ['$group' => [
    *              '_id' => '$user_id', 
    *               'sum' => ['$sum' => 1],
    *              'real_amount' => ['$sum' => '$real_amount'],
    *             'user_id' => ['$last'=>'$user_id'],
    *                'openid' => ['$first'=>'$openid'],
    *                ],
                    
    *            ],
    *             [
    *                 '$skip'=>1
    *             ],
    *             [
    *                 '$limit'=>1
    *             ]
    *        ],
    *        'cursor' => new \stdClass,
     *      ];
     * @author wuxian
     * @since 2020-04-20
     */
    public function execute($pipeline)
    {
        $command = new Command($pipeline);
        $namespace = $this->dbname;
        $cursor = $this->manager->executeCommand($namespace, $command);
        return $cursor->toArray();
    }

    
}